﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using HtmlAgilityPack;

namespace iTunes.Scrubber.DataSources
{
    public class IMDBSource : BaseClasses.InternalSingletonBase<IMDBSource>, Interfaces.IDataSource
    {
        /// <summary>
        /// Mapping of IMDB_IDs to cached Episode Lists
        /// </summary>
        private Dictionary<String, HtmlDocument> _episodeLists;

        /// <summary>
        /// Constructor for the IMDB DataSource.
        /// </summary>
        public IMDBSource()
        {
            this._episodeLists = new Dictionary<String, HtmlDocument>();
        }

        /// <summary>
        /// Clean up any open object references.
        /// </summary>
        public void Dispose() { }

        /// <summary>
        /// Search for, or return cached instance of data about a series,
        /// obtained by scraping the IMDB site.
        /// </summary>
        /// <param name="imdb_id">The ID of the IMDB content to load.</param>
        /// <returns>IMDBData containing the results of the search.</returns>
        public IMDBData this[String imdb_id]
        {
            get
            {
                if (String.IsNullOrWhiteSpace(imdb_id))
                    return null;

                if (!this._episodeLists.ContainsKey(imdb_id))
                {
                    Console.WriteLine("Loading [{0}] from IMDB", imdb_id);

                    String search = Helpers.FileHelper.HttpGet(String.Format("http://www.imdb.com/title/{0}/episodes", imdb_id));

                    if (String.IsNullOrWhiteSpace(search))
                        return null;
                    
                    HtmlDocument imdb = new HtmlDocument();

                    imdb.LoadHtml(search);

                    this._episodeLists[imdb_id] = imdb;
                }

                return new IMDBData()
                {
                    IMDB_ID = imdb_id,
                    EpisodeListPage = this._episodeLists[imdb_id]
                };
            }
        }

        public class IMDBData
        {
            /// <summary>
            /// The IMDB_ID of the current data.
            /// </summary>
            public String IMDB_ID { get; set; }

            /// <summary>
            /// The content of the HTML response to the search for the series.
            /// </summary>
            public HtmlDocument EpisodeListPage { get; set; }
        }

        public IEnumerable<MediaItems.TVShowItem> GetEpisodes(String series, Delegates.Filter<MediaItems.TVShowItem> filter = null, Delegates.Sorter<MediaItems.TVShowItem> sorter = null, params Delegates.Transformer<MediaItems.TVShowItem>[] transforms)
        {
            String imdb_id = DataSources.TVDBSource.Instance[series].IMDB_ID;

            if (imdb_id == null)
                return Enumerable.Empty<MediaItems.TVShowItem>();

            return (from episode in this[imdb_id].EpisodeListPage.DocumentNode.SelectNodes("//div/div//h3[contains(text(), 'Episode')]/a")
                    let match = Regex.Match(HttpUtility.HtmlDecode(episode.ParentNode.InnerText), @"Season (\d+), Episode (\d+): (.*)", RegexOptions.IgnoreCase)
                    where match.Success
                    let mediaItem = new MediaItems.TVShowItem()
                    {
                        IMDB_ID = imdb_id,
                        Show = series,
                        Season = Int32.Parse(match.Groups[1].Value),
                        Episode = Int32.Parse(match.Groups[2].Value),
                        Title = match.Groups[3].Value
                    }
                    orderby sorter == null ? mediaItem : sorter(mediaItem)
                    select mediaItem);
        }
    }
}
